package modules

import (
	"encoding/binary"
	"errors"
	"fmt"
	"encoding/hex"
	"sync"
	"os"
	"adai.design/homemaster/log"
	"io"
	"time"
)

//
// (go)homemaster与(c)/dev/master通信格式
//  TLV - Type(uint8) - Length(uint16) - Value([]byte)
//
type MasterMessage struct {
	pkgType uint8
	data []byte
}

func (m *MasterMessage) String() string {
	data, err := messageMarshal(m)
	if err != nil {
		return ""
	}
	return hex.EncodeToString(data)
}

func messageMarshal(m *MasterMessage) ([]byte, error) {
	msg := make([]byte, len(m.data) + 3)
	msg[0] = m.pkgType
	binary.BigEndian.PutUint16(msg[1:], uint16(len(m.data)))
	copy(msg[3:], m.data)
	return msg[:], nil
}

func messageUnmarshal(data []byte) (*MasterMessage, error) {
	if len(data) < 3 {
		return nil, errors.New(fmt.Sprintf("invalid packets, msg(%x)", data))
	}

	l := binary.BigEndian.Uint16(data[1:])
	if int(l) + 3 != len(data) {
		return nil, errors.New(fmt.Sprintf("illegal data length, msg(%x)", data))
	}

	return &MasterMessage{
		pkgType: data[0],
		data: data[3:],
	}, nil
}

type MasterObserverFunc func(m *MasterMessage) error

// 驱动链接客户端
type masterClient struct {
	sync.Mutex
	observers map[byte]MasterObserverFunc

	task chan []byte
	dev 	 *os.File
}

func (m *masterClient) readMessage() {
	buffer := make([]byte, MasterMessageMaxLen)
	for {
		n, err := m.dev.Read(buffer)
		if err != nil {
			if err == io.EOF {
				continue
			} else {
				log.Error("%v", err)
				break
				//log.Panic(err)
			}
		}

		msg, err := messageUnmarshal(buffer[:n])
		if err != nil {
			//log.Println("err: ", err)
			continue
		}

		m.Lock()
		if f, ok := m.observers[msg.pkgType]; ok {
			if err = f(msg); err != nil {
				log.Println("err: ", err)
			}
		} else {
			log.Printf("unknown msg: %s\n", msg.String())
		}
		m.Unlock()

	}
}

func (m *masterClient) executeTask() {
	for task := range m.task {
		//if task[0] == MasterRadio {
		//	log.Printf("task: %x\n", task)
		//}
		if m.dev != nil {
			if _, err := m.dev.Write(task); err != nil {
				log.Fatal("err: ", err)
			}
			time.Sleep(time.Microsecond * 10)

		}
	}
}

// master client
var master = masterClient{
	observers: make(map[byte]MasterObserverFunc),
	task: make(chan []byte, 10),
}

func addObserver(msgType uint8, f MasterObserverFunc) {
	master.Lock()
	defer master.Unlock()
	master.observers[msgType] = f
}

func removeObserver(msgType uint8) {
	master.Lock()
	defer master.Unlock()
	delete(master.observers, msgType)
}

func MasterOpen() error {
	f, err := os.OpenFile(MasterDevPath, os.O_RDWR, 0666)
	if err != nil {
		return err
	}
	master.dev = f

	go master.readMessage()
	go master.executeTask()

	return nil
}

func MasterClose() error {
	master.Lock()
	defer master.Unlock()

	if master.dev != nil {
		master.dev.Close()
	}

	for k := range master.observers {
		delete(master.observers, k)
	}

	close(master.task)
	master.task = nil
	return nil
}

func masterSendMessage(msg *MasterMessage) error {
	if master.task == nil {
		return errors.New("task channel has been closed")
	}

	task, _ := messageMarshal(msg)
	master.task <- task
	return nil
}

func MasterSendTask(msg *MasterMessage) error {
	if master.task == nil {
		return errors.New("task channel has been closed")
	}
	task, _ := messageMarshal(msg)
	master.task <- task
	return nil
}

